iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
1
Software Development

為什麼世界需要Typescript系列 第 18

狀態模式(State Pattern) - 18

  • 分享至 

  • xImage
  •  

接下來建立 enum 列舉描述有哪些狀態

enum VendingState {
   Vending,
   SoldOut,
   InsertingCoins
}

接下來建立一個變數, 設定目前的狀態

class VendingMachine {
   private _state: VendingState = VendingState.Vending;
}

再將所有公開方法(function) 依照這個狀態做改變行為

insertMoney(money: number): number {
   if( this._state == VendingState.Vending ) {
      ...
   } else if ( this._state == VendingState.SoldOut ) {
      ...
   } else {
      ...
   }

就像上面, 我們先把所有公開方法(function) 按照if-else 判斷在每一個狀態中, 只考慮自己本身的方法行為是甚麼. 不用考慮其他公開方法(function) 的行為.

例如投幣的方法insertMoney 我們可以把這個方法寫成

insertMoney(money: number): number {
   if( this._state == VendingState.SoldOut ) {
      return money;
   } else if( this._state == VendingState.Vending ) {
      this._amount = money;
      if( this._amount >= this._price ){
         this.vendingLed = true;
         this.ledScreen = `已投${this._amount} 元, 請按下購買`;
      } else {
         this.ledScreen = `已投${this._amount} 元, 請繼續投幣`; 
      }
      this._state = VendingState.InsertingCoins;
      return 0;
   } else if( this._state == VendingState.InsertingCoins ) {
      if( this._amount >= this._price ){
         this.vendingLed = true;
         this.ledScreen = `已投${this._amount} 元, 請按下購買`;
         return money;
      } else {
         this.vendingLed = false;
         this._amount += money;
         this.ledScreen = `已投${this._amount} 元, 請繼續投幣`;
         return 0;
      }
   }
} 

投幣的行為會因為每一個狀態不同所對應的處理動作也不同, 上面程式碼寫出

  • 當販賣機在 "已售完" 的狀態下, 無論你投幣多少錢, 它就吐出多少錢.
  • 當販賣機在 "販賣中" 的狀態下, 只要一投幣進去, 不退錢, 並且馬上設定販賣機的狀態改為 "投幣中".
  • 當販賣機在 "投幣中" 的狀態下, 投幣功能只判斷投幣進去的金額是否有達到飲料商品的售價.

接下來我們來實踐buyButton 方法, 同樣地buyButton 方法中也針對每一個狀態進行不同所對應的處理動作.

buyButton(): [boolean, number] {
   if( this._state == VendingState.SoldOut ) {
      return [false, 0];
   } else if( this._state == VendingState.Vending ) {
      return [false, 0];
   } else if( this._state == VendingState.InsertingCoins ) {
      if( this._amount >= this._price ){
         let refund = this._amount - this._price;
         this._state = VendingState.Vending;
         return [true, refund];
      } else {
         return [false, 0];
      }
   }
}

取消購買方法也按照這模式修改

cancel(): number {
   if( this._state == VendingState.SoldOut ) {
      return 0;
   } else if( this._state == VendingState.Vending ) {
      return 0;
   } else if( this._state == VendingState.InsertingCoins ) {
      if( this._inventory > 0 ) {
         this.ledScreen = `庫存${this._inventory} 瓶, 請投幣購買`;
         this._state = VendingState.Vending
      } else {
         this.ledScreen = `飲料已售完`; 
         this._state = VendingState.SoldOut;
      }
      let refund = this._amount;
      this._amount = 0;
      return refund;
   }
}

好, 先不管程式碼邏輯到底有沒有正確, 觀察以上程式碼, 我們可以看到這幾個公開方法(function) 裡面都有針對每一種狀態做不同處理的動作.

下一步我們要消滅許多if-else , 之前有提到過如何消滅if-else 方法. 所以我們要定義一個抽象類別(Class) , 在這個抽象類別內, 每個動作都有一個對應的方法.


上一篇
狀態模式(State Pattern) - 17
下一篇
狀態模式(State Pattern) - 19
系列文
為什麼世界需要Typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言